home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 101-125 / scopedisk102 / hamsharp / hamsharp.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  22KB  |  835 lines

  1. /* Copyright (C) 1989 by Ken C.M. Lau.
  2. ** Permission to use, copy, and distribute this software and its
  3. ** documentation for any purpose and without fee is hereby granted.
  4. **
  5. ** Author   : Ken Lau. June 89
  6. ** Purpose  : Convert GIF file to IFF ham file
  7. ** Compiler : Aztec C 4.3a
  8. **             cc hamsharp.c
  9. **             cc hamsharp2.c
  10. **             cc hamsharp3.c
  11. **             cc hamsharp4.c
  12. **             ln hamsharp.o hamsharp2.o hamsharp3.o hamsharp4.o -lc -lm
  13. */
  14.  
  15. #include <stdio.h>
  16.  
  17. struct rgb {int r, g, b;};
  18. struct remapelement {int pal, dist;};
  19.  
  20. long colorerr [256];       /* Histogram of errors */
  21. long imageerr = 0L;        /* Total error */
  22. int colors;                /* Colors in source */
  23. int pals;                  /* Number of palette colors currently defined */
  24. int planes;                /* Planes in destination */
  25. int hamflag;               /* Set if picture requires HAM */
  26. int picstep;               /* Horizontal source pixels per dest pixel */
  27. int picwidth;              /* Destination pixels per line */
  28. int scanstep = 2;          /* Increase for faster processing */
  29. int hamonly = 0;           /* Set to process skip processing non-HAM */
  30. int compression = -1;      /* Set to 0 to switch off IFF compression */
  31. int filenote = 0;          /* Set to -1 to note error */
  32. int edge = 1;              /* Set to 0 for edge smoothing algorithm */
  33. int update = 0;            /* Set to 1 for skip existing files */
  34. short iffbufsize = 16384;  /* Default output file buffer size */
  35. struct rgb palette [32];   /* Destination palette */
  36. unsigned char **pic = NULL; /* Pointer to decompressed image in RAM */
  37. struct remapelement remap [256]; /* Closest palette color to given color */
  38. char gifname [80], iffname [80]; /* Source and destination files */
  39. FILE *gif, *iff;
  40. char *iffbuf = NULL;       /* Pointer to output buffer */
  41.  
  42. /* GIF header info */
  43. char signature [6];
  44. struct {
  45.    unsigned width;
  46.    unsigned height;
  47.    unsigned char pixel;
  48.    unsigned char background;
  49.    unsigned char reserved;
  50. }  screen;
  51. struct rgb cmap [256];
  52. struct {
  53.    unsigned char seperator;
  54.    unsigned left;
  55.    unsigned top;
  56.    unsigned width;
  57.    unsigned height;
  58.    unsigned char pixel;
  59. }  image;
  60.  
  61. /* Main. Source and destination filenames may be specified in command line */
  62. main(argc, argv)
  63. char *argv[];
  64. {
  65.    int bestcolor;
  66.  
  67.    getargs(argc, argv);   /* Set filenames */
  68.    initvars();   /* Allocate and initialize tables and variables */
  69.    while (getlist(gifname, iffname)) {
  70.       printf("Converting %s-->%s\n", gifname, iffname);
  71.       if (!readgif())        /* Decompress file into RAM pointed by pic */
  72.          goto nextfile;
  73.       palette [0] = cmap [0]; /* Background color is always assigned */
  74.       if (hamflag) {
  75.          if (edge) {
  76.             for (pals = 1; pals < 16; pals++) {
  77.                calcremap();  /* Calculate closest palette colors to remap to */
  78.                scanpic();    /* Scan pic and set colorerr [] */
  79.                bestcolor = findbest();   /* Pick a color to assign to palette */
  80.                palette [pals] = cmap [bestcolor];
  81.                printf("Palette %2d = colour %3d\x0D", pals, bestcolor);
  82.                printf("\x1B[40CImageErr = %7ld\n\x1BM", imageerr);
  83.             }
  84.             printf("\x1B[80K");
  85.          }
  86.          else
  87.             setpalette();
  88.       }
  89.       else {
  90.          for (pals = 1; pals < colors; pals++)
  91.             palette [pals] = cmap [pals];
  92.       }
  93.       calcremap();
  94.       if (!writeiff())    /* Use palette [] and remap [] */
  95.          goto nextfile;
  96.       printf("\x1B[1F\x1B[40K"); /* Erase image size stats */
  97.       printf("\x1BM\x1B[56C");
  98.       printf("ImageErr=%ld\n", imageerr);
  99. nextfile:
  100.       freepic(); /* Free memory if required */
  101.    }
  102.    freevars();
  103. }
  104.  
  105. /* Allocate and initialize tables and variables */
  106. initvars()
  107. {
  108.    char *calloc();
  109.  
  110.    /* Allocate memory for file buffers */
  111.    iffbuf = calloc(iffbufsize, sizeof(char));
  112.    if (iffbuf == NULL)
  113.       fatalerr("Out of memory");
  114.    initrgberr();
  115. }
  116.  
  117. /* Free memory for lookup tables */
  118. freevars ()
  119. {
  120.    if (iffbuf != NULL) {
  121.       free (iffbuf);
  122.       iffbuf = NULL;
  123.    }
  124.    freergberr ();
  125. }
  126.  
  127. /* Print title page, get arguments from user if required */
  128. getargs (argc, argv)
  129. char *argv [];
  130. {
  131.    int i;
  132.  
  133.    printf ("\n");
  134.    printf ("        HAMSHARP 1.5, GIF to IFF HAM converter, KL\n");
  135.    printf ("        ------------------------------------------\n");
  136.    printf ("\n");
  137.  
  138.    initlist ();
  139.    gifname[0] = iffname[0] = '\0';
  140.    for (i = 1; i < argc; i++)
  141.       if (argv[i][0] == '-') {
  142.          switch (tolower (argv[i][1])) {
  143.          case 's':
  144.             sscanf (argv[i], "%*c%*c%d", &scanstep);
  145.             break;
  146.          case 'h':
  147.             hamonly = -1;
  148.             break;
  149.          case 'c':
  150.             compression = 0;
  151.             break;
  152.          case 'b':
  153.             sscanf (argv [i], "%*c%*c%d", &iffbufsize);
  154.             break;
  155.          case 'f':
  156.             filenote = -1;
  157.             break;
  158.          case 'd':
  159.             edge = 0;
  160.             break;
  161.          case 'e':
  162.             edge = -1;
  163.             break;
  164.          case 'u':
  165.             update = -1;
  166.             break;
  167.          default:
  168.             fatalerr ("Illegal option");
  169.             break;
  170.          }
  171.       }
  172.       else {
  173.          if (gifname[0] == '\0') strcpy (gifname, argv[i]);
  174.          else if (iffname [0] == '\0') strcpy (iffname, argv[i]);
  175.       }
  176.    printf ("Source GIF filespec? ");
  177.    if (gifname [0] == '\0')
  178.       scanf ("%s", gifname);
  179.    else
  180.       printf ("%s\n", gifname);
  181.  
  182.    printf ("Destn  IFF filespec? ");
  183.    if (iffname [0] == '\0')
  184.       scanf ("%s", iffname);
  185.    else
  186.       printf ("%s\n", iffname);
  187.  
  188.    if (scanstep <= 0)
  189.       fatalerr ("Scan step must be greater than 0");
  190.  
  191.    getwild (); /* Read filenames matching wildcard from disk */
  192.                /* and add to list */
  193.    printf ("\n");
  194. }
  195.  
  196. /* Decompress GIF file into RAM. Return error status */
  197. readgif ()
  198. {
  199.    if ((gif = fopen (gifname, "r")) == NULL) {
  200.       printf ("GIF file not found\n");
  201.       return (0);
  202.    }
  203.  
  204.    if (!readheader ())
  205.       return (0);
  206.    if (hamonly && !hamflag) {
  207.       fclose (gif);
  208.       printf ("\x1BM\x1B[40K\x1BM\x1B[56C");
  209.       printf ("Not HAM\n");
  210.       return (0);
  211.    }
  212.    readpic ();
  213.    fclose (gif);
  214.    return (-1);
  215. }
  216.  
  217. /* Print error message and halt */
  218. fatalerr (s)
  219. char *s;
  220. {
  221.    printf (s);
  222.    printf ("\n");
  223.    freepic ();
  224.    freelist ();
  225.    freevars ();
  226.    exit (20);
  227. }
  228.  
  229. /* Read header. Return error status */
  230. readheader ()
  231. {
  232.    int   color;
  233.  
  234.    fread (signature, 1, 6, gif);
  235.    if (strncmp (signature, "GIF87a", 6) != 0) {
  236.       printf ("Not GIF file\n");
  237.       return (0);
  238.    }
  239.  
  240.    screen.width = readint ();
  241.    screen.height = readint ();
  242.    screen.pixel = getc (gif);
  243.    screen.background = getc (gif);
  244.    screen.reserved = getc (gif);
  245.  
  246.    colors = 1 << ((screen.pixel & 0x07) + 1);
  247.    for (color = 0; color < colors; color++) {
  248.       cmap [color].r = getc (gif) >> 4;
  249.       cmap [color].g = getc (gif) >> 4;
  250.       cmap [color].b = getc (gif) >> 4;
  251.    }
  252.  
  253.    image.seperator = getc (gif);
  254.    image.left = readint ();
  255.    image.top = readint ();
  256.    image.width = readint ();
  257.    image.height = readint ();
  258.    image.pixel = getc (gif);
  259.  
  260.    if (image.seperator != ',') {
  261.       printf ("Missing seperator\n");
  262.       return (0);
  263.    }
  264.    if ((image.pixel & 0x80) != 0) {
  265.       printf ("Cannot handle local color map\n");
  266.       return (0);
  267.    }
  268.    printf ("%ux%ux%u\n", image.width, image.height, colors);
  269.  
  270.    picstep = 1;
  271.    picwidth = image.width;
  272.    hamflag = (colors > 32) || ((colors > 16) && (image.width > 320));
  273.    if (hamflag && (image.width > 320)) {
  274.       picstep = 2;
  275.       picwidth = image.width / picstep;
  276.    }
  277.    planes = hamflag ? 6 : (screen.pixel & 7) + 1;
  278.    return (-1);
  279. }
  280.  
  281. /* Read 16 bit quantity from GIF file, low byte first */
  282. readint ()
  283. {
  284.    int temp;
  285.  
  286.    temp = getc (gif);
  287.    temp |= getc (gif) << 8;
  288.    return (temp);
  289. }
  290.  
  291. unsigned char codesize;  /* Used by readpic() and readcode() */
  292.  
  293. /* Read from gif file and write to iff file */
  294. readpic()
  295. {
  296.    int   i;
  297.    int   code, maxcode, clearcode, eofcode, curcode, oldcode, incode;
  298.    int   freecode, firstfree;
  299.    unsigned char initcodesize, finchar, bitmask, *outptr;
  300.    static int prefix [4096];
  301.    static unsigned char suffix [4096], outcode [1025];
  302.  
  303.    openadd ();
  304.    openreadcode ();
  305.  
  306.    outptr = outcode;
  307.    bitmask = (1 << ((screen.pixel & 7) + 1)) - 1;
  308.  
  309.    codesize = getc (gif);
  310.    clearcode = (1 << codesize);
  311.    eofcode = clearcode + 1;
  312.    freecode = firstfree = clearcode + 2;
  313.    
  314.    codesize++;
  315.    initcodesize = codesize;
  316.    maxcode = (1 << codesize);
  317.  
  318.    code = readcode ();
  319.    while (code != eofcode)
  320.    {
  321.       if (code == clearcode)
  322.       {
  323.          codesize = initcodesize;
  324.          maxcode = (1 << codesize);
  325.          freecode = firstfree;
  326.          curcode = oldcode = code = readcode ();
  327.          finchar = curcode;
  328.          addpixel (finchar);
  329.       }
  330.       else
  331.       {
  332.          curcode = incode = code;
  333.  
  334.          if (curcode >= freecode)
  335.          {
  336.             curcode = oldcode;
  337.             *outptr++ = finchar;
  338.          }
  339.  
  340.          while (curcode > bitmask)
  341.          {
  342. #ifdef CHECK
  343.             if (outptr > outcode + 1024)
  344.                fatalerr ("Corrupt GIF file");
  345. #endif
  346.             *outptr++ = suffix [curcode];
  347.             curcode = prefix [curcode];
  348.          }
  349.  
  350.          finchar = curcode;
  351.          addpixel (finchar);
  352.  
  353.          while (outptr != outcode)
  354.             addpixel (*--outptr);
  355.  
  356.          prefix [freecode] = oldcode;
  357.          suffix [freecode] = finchar;
  358.          oldcode = incode;
  359.  
  360.          if (++freecode >= maxcode)
  361.          {
  362. #ifdef CHECK
  363.             if (codesize < 12)
  364.             {
  365. #endif
  366.                codesize ++;
  367.                maxcode <<= 1;
  368. #ifdef CHECK
  369.             }
  370. #endif
  371.          }
  372.       }
  373.       code = readcode ();
  374.    }
  375.  
  376.    if (getc (gif) != 0)
  377.       printf ("Warning: unaligned packet\n");
  378.  
  379.    closereadcode ();
  380.    closeadd ();
  381. }
  382.  
  383. static unsigned char bitmask = 0x00;
  384. static int bytecount = 0;
  385.  
  386. /* Prepare to call readcode */
  387. openreadcode ()
  388. {
  389.    bytecount = bitmask = 0;
  390. }
  391.  
  392. /* Fetch the next few bit from the source gif file */
  393. readcode ()
  394. {
  395.    static unsigned dsttbl [13] =
  396.       {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
  397.        0x0100, 0x0200, 0x0400, 0x0800, 0x1000 };
  398.    static unsigned dstmasked = 0x0800;
  399.    static unsigned dstmask = 0x0001;
  400.    static int bytebuf = 0;
  401.    static unsigned temp;
  402.  
  403.    temp = 0;
  404.    dstmasked = dsttbl [codesize];
  405.    for (dstmask = 0x0001; dstmask != dstmasked; dstmask <<= 1)
  406.    {
  407.       if (!bitmask)
  408.       {
  409.          bitmask = 0x01;
  410.          if (bytecount == 0)
  411.             bytecount = getc (gif);
  412.          bytebuf = getc (gif);
  413.          bytecount--;
  414.       }
  415.       if (bytebuf & bitmask)
  416.          temp |= dstmask;
  417.       bitmask <<= 1;
  418.    }
  419.    return (temp);
  420. }
  421.  
  422. /* Finish reading code */
  423. closereadcode ()
  424. {
  425. }
  426.  
  427. int xpic, ypic, xstate, leavepass;
  428. unsigned char *linestart;
  429.  
  430. /* Prepare to add pixels to pic */
  431. openadd ()
  432. {
  433.    char *calloc ();
  434.    int y;
  435.  
  436.    xpic = ypic = xstate = leavepass = 0;
  437.    if (image.pixel & 0x40)
  438.       leavepass = 2; /* GIF interleaved */
  439.    /* Allocate memory for the whole picture */
  440.    pic = (unsigned char **) calloc (image.height, sizeof (unsigned char *));
  441.    if (pic == NULL)
  442.       fatalerr ("Out of memory");
  443.    for (y = 0; y < image.height; y++) {
  444.       pic [y] = (unsigned char *) calloc (picwidth, sizeof (unsigned char));
  445.       if (pic [y] == NULL)
  446.          fatalerr ("Out of memory");
  447.    }
  448.    linestart = pic [0];
  449.    printf ("Decompressing line\n");
  450. }
  451.  
  452. /* Add pixels to pic in RAM */
  453. addpixel (pix)
  454. {
  455.    static step [8]  = {1, 0, 8, 8, 4, 2, 0};  /* GIF interleaved consts */
  456.    static first [8] = {0, 0, 0, 4, 2, 1, 0};
  457.  
  458.    if (!xstate) {
  459.       xstate = picstep;
  460.       *linestart++ = pix;
  461.    }
  462.    xstate--;
  463.    xpic++;
  464.    if (xpic >= image.width) {
  465.       printf ("%3d\n\x1BM", ypic);
  466.       xpic = 0;
  467.       ypic += step [leavepass];
  468.       if (ypic >= image.height)
  469.          ypic = first [++leavepass];
  470.       linestart = pic [ypic];
  471.    }
  472. }
  473.  
  474. /* Stop add pixels to RAM */
  475. closeadd ()
  476. {
  477.    printf ("   \x1B[1F\x1B[40K\n\x1BM");
  478. }
  479.  
  480. /* Free memory for picture */
  481. freepic ()
  482. {
  483.    int y;
  484.  
  485.    if (pic == NULL)
  486.       return;
  487.    for (y = 0; y < image.height; y++)
  488.       free (pic [y]);
  489.    free (pic);
  490.    pic = NULL;
  491. }
  492.  
  493. /* Calculate nearest palette color to given color */
  494. calcremap ()
  495. {
  496.    int color, pal, minpal, mindistance, distance, r, g, b;
  497.    int maxdistance = rgberr (0, 0, 0, 15, 15, 15);
  498.    struct rgb *c, *p;
  499.  
  500.    for (color = 0; color < colors; color++) {
  501.       r = (c = & cmap [color]) -> r;
  502.       g = c->g;
  503.       b = c->b;
  504.       minpal = 0;
  505.       mindistance = maxdistance;
  506.       for (pal = 0; pal < pals; pal++) {
  507.          p = & palette [pal];
  508.          distance = rgberr (r, g, b, p->r, p->g, p->b);
  509.          if (distance < mindistance) {
  510.             mindistance = distance;
  511.             minpal = pal;
  512.          }
  513.       }
  514.       remap [color].pal = minpal;
  515.       remap [color].dist = mindistance;
  516.    }
  517. }
  518.  
  519. /* Accumulate the error due to each color in the source image */
  520. scanpic ()
  521. {
  522.    unsigned char *linestart, *lineend;
  523.    int color, y, pix, select, gunerr, gunerr2, gunerr3;
  524.    struct rgb gun, want;
  525.    struct remapelement *remapp;
  526.  
  527.    for (color = 0; color < colors; color++)
  528.       colorerr [color] = 0L;
  529.    for (y = 0; y < image.height; y += scanstep) {
  530.       gun = palette [0];
  531.       lineend = (linestart = pic [y]) + picwidth;
  532.       while (linestart != lineend) {
  533.          pix = *linestart++;
  534.          if (! (remapp = & remap [pix]) -> dist)
  535.             gun = palette [remapp->pal];
  536.          else {
  537.             want = cmap [pix];
  538.             gunerr  = rgberr (want.r, gun.g, gun.b, want.r, want.g, want.b);
  539.             gunerr2 = rgberr (gun.r, want.g, gun.b, want.r, want.g, want.b);
  540.             gunerr3 = rgberr (gun.r, gun.g, want.b, want.r, want.g, want.b);
  541.             select = 0;
  542.             if (gunerr2 < gunerr) {
  543.                gunerr = gunerr2;
  544.                select = 1;
  545.             }
  546.             if (gunerr3 < gunerr) {
  547.                gunerr = gunerr3;
  548.                select = 2;
  549.             }
  550.             *(&gun.r + select) = *(&want.r + select);
  551.  
  552.             if (remapp->dist < gunerr) {
  553.                gunerr = remapp->dist;
  554.                gun = palette [remapp->pal];
  555.             }
  556.             colorerr [pix] += gunerr;
  557.          }
  558.       }
  559.    }
  560. }
  561.  
  562. /* Select colour to assign to palette given colorerr [] */
  563. findbest ()
  564. {
  565.    int bestcolor = 0;
  566.    long besterror = 0L;
  567.    int color;
  568.  
  569.    imageerr = 0L; /* Estimated */
  570.    for (color = 0; color < colors; color++) {
  571.       if (colorerr [color] >= besterror) {
  572.          besterror = colorerr [color];
  573.          bestcolor = color;
  574.       }
  575.       imageerr += colorerr [color];
  576.    }
  577.    imageerr = (imageerr - besterror) * scanstep;
  578.    return (bestcolor);
  579. }
  580.  
  581. /* Write IFF file from image in RAM given pic and remap [] */
  582. /* Return error status */
  583. writeiff ()
  584. {
  585.    static char noteline [120];
  586.  
  587.    if ((iff = fopen (iffname, "w")) == NULL) {
  588.       printf ("Cannot write to IFF file\n");
  589.       return (0);
  590.    }
  591.  
  592.    /* Set up buffer for output */
  593.    if (iff->_buff)
  594.       fatalerr ("IFF buffer already allocated"); /* Should never occur */
  595.    iff->_buff = iffbuf;
  596.    iff->_buflen = iffbufsize;
  597.  
  598.    writeheader ();
  599.    writepic ();      /* with optional compression */
  600.    fixupheader ();   /* body and form lengths fixups */
  601.    fclose (iff);
  602.  
  603.    sprintf (noteline, "Err=%ld", imageerr);
  604.    if (filenote)
  605.       SetComment (iffname, noteline);
  606.    return (-1);
  607. }
  608.  
  609. long formlenpsn, bodylenpsn;
  610.  
  611. /* Write header to IFF file */
  612. writeheader ()
  613. {
  614.    long ftell ();
  615.    int pal;
  616.  
  617.    fputs ("FORM", iff); formlenpsn = ftell (iff); writelong (0L);
  618.    fputs ("ILBM", iff);
  619.  
  620.    fputs ("BMHD", iff); writelong (20L);
  621.    writeint (picwidth); writeint (image.height);   /* w, h */
  622.    writeint (image.left / picstep);                /* x, y */
  623.    writeint (image.top);
  624.    putc (planes, iff);                 /* bitplanes */
  625.    putc (0, iff);                      /* masking */
  626.    putc (compression ? 1 : 0, iff);    /* compression */
  627.    putc (0, iff);                      /* pad1 */
  628.    writeint (0);                       /* transparent color */
  629.    putc (10, iff); putc (11, iff);     /* xAspect, yAspect */
  630.    writeint (screen.width / picstep);  /* pagewidth, pageheight */
  631.    writeint (screen.height);
  632.  
  633.    if (hamflag) {
  634.       fputs ("CAMG", iff); writelong (4L);
  635.       writelong (screen.height > 200 ? 0x4804L : 0x4800L);
  636.    }
  637.  
  638.    fputs ("CMAP", iff); writelong ((long)(pals * 3));
  639.    for (pal = 0; pal < pals; pal++) {
  640.       putc (palette [pal].r << 4, iff);
  641.       putc (palette [pal].g << 4, iff);
  642.       putc (palette [pal].b << 4, iff);
  643.    }
  644.    fputs ("BODY", iff); bodylenpsn = ftell (iff); writelong (0L);
  645. }
  646.  
  647. /* Write long integer to IFF file, high byte first */
  648. writelong (a)
  649. long a;
  650. {
  651.    writeint ((unsigned) (a >> 16));
  652.    writeint ((unsigned) a);
  653. }
  654.  
  655. /* Write unsigned integer to IFF file, high byte first */
  656. writeint (a)
  657. unsigned a;
  658. {
  659.    putc (a >> 8, iff);
  660.    putc (a & 0xFF, iff);
  661. }
  662.  
  663. /* Fixup IFF header */
  664. fixupheader ()
  665. {
  666.    long ftell ();
  667.    long bodylen = ftell (iff) - bodylenpsn - 4L;
  668.    long formlen = ftell (iff) - formlenpsn - 4L;
  669.  
  670.    fseek (iff, bodylenpsn, 0); writelong (bodylen);
  671.    fseek (iff, formlenpsn, 0); writelong (formlen);
  672.    fseek (iff, 0L, 2);
  673. }
  674.  
  675. /* Write out body of IFF file with optional compression */
  676. writepic ()
  677. {
  678.    long ftell ();
  679.    unsigned char *linestart, *lineend;
  680.    int y, pix, select, gunerr, gunerr2, gunerr3, colmask, planemask;
  681.    struct rgb gun, want;
  682.    struct remapelement *remapp;
  683.    int cols = (picwidth + 7) / 8;
  684.    static char pl[6][256];
  685.    static bitpsn, col, plane;
  686.    static compbuf [128];
  687.    static compbufi, compbufi1, compbufi2, state, disp, data;
  688.    static hambit [3] = {0x20, 0x30, 0x10};
  689.  
  690.    imageerr = 0L;
  691.    printf ("Writing line\n");
  692.    for (y = 0; y < image.height; y++) {
  693.       printf ("%3d\n\x1BM", y);
  694.       col = 0;
  695.       colmask = 0x80;
  696.       gun = palette [0];
  697.       lineend = (linestart = pic [y]) + picwidth;
  698.       while (linestart != lineend) {
  699.          pix = *linestart++;
  700.          if (! (remapp = & remap [pix]) -> dist)
  701.             gun = palette [data = remapp->pal];
  702.          else {
  703.             want = cmap [pix];
  704.             gunerr  = rgberr (want.r, gun.g, gun.b, want.r, want.g, want.b);
  705.             gunerr2 = rgberr (gun.r, want.g, gun.b, want.r, want.g, want.b);
  706.             gunerr3 = rgberr (gun.r, gun.g, want.b, want.r, want.g, want.b);
  707.             select = 0;
  708.             if (gunerr2 < gunerr) {
  709.                gunerr = gunerr2;
  710.                select = 1;
  711.             }
  712.             if (gunerr3 < gunerr) {
  713.                gunerr = gunerr3;
  714.                select = 2;
  715.             }
  716.             data = hambit [select]
  717.                  | (*(&gun.r + select) = *(&want.r + select));
  718.             if (remapp->dist < gunerr) {
  719.                gunerr = remapp->dist;
  720.                gun = palette [data = remapp->pal];
  721.             }
  722.             imageerr += gunerr;
  723.          }
  724.          planemask = 0x01;
  725.          for (plane = 0; plane < planes; plane++) {
  726.             if (data & planemask)
  727.                pl [plane][col] |= colmask;
  728.             planemask <<= 1;
  729.          }
  730.          if (colmask == 0x01) {
  731.             colmask = 0x80;
  732.             col++;
  733.          }
  734.          else
  735.             colmask >>= 1;
  736.       }
  737.  
  738.       if (!compression) {
  739.          for (plane = 0; plane < planes; plane++) {
  740.             for (col = 0; col < cols; col++) {
  741.                putc (pl [plane][col], iff);
  742.                pl [plane][col] = 0;
  743.             }
  744.             if (ftell (iff) & 1L)
  745.                putc (0, iff);
  746.          }
  747.          goto nextline;
  748.       }
  749.       for (plane = 0; plane < planes; plane ++) {
  750.          compbufi = 0;
  751.          state = 0;
  752.          data = pl[plane][0];
  753.          for (col = 1; col < cols; col ++)
  754.             switch (state) {
  755.                case 0:
  756.                   if (data == pl[plane][col]) {
  757.                      state = 1;
  758.                      compbuf [compbufi] = col - 2 - compbufi;
  759.                      compbufi = col - 1;
  760.                   }
  761.                   else
  762.                      data = pl[plane][col];
  763.                   break;
  764.                case 1:
  765.                   if (data != pl[plane][col]) {
  766.                      state = 0;
  767.                      compbuf [compbufi] = compbufi - col + 1;
  768.                      compbufi = col;
  769.                      data = pl[plane][col];
  770.                   }
  771.                   break;
  772.             }
  773.          compbuf [compbufi] =
  774.             (state==0) ? cols-compbufi-1 : compbufi-cols+1;
  775.          state = 0;
  776.          compbufi = 0;
  777.          while (compbufi < cols) {
  778.             disp = compbuf [compbufi];
  779.             switch (state) {
  780.                case 0:
  781.                   if (disp >= 0) {
  782.                      state = 1;
  783.                      compbufi1 = compbufi;
  784.                   }
  785.                   break;
  786.                case 1:
  787.                   if (disp < 0) {
  788.                      state = 2;
  789.                      compbufi2 = compbufi;
  790.                   }
  791.                   else
  792.                      compbufi1 = compbufi;
  793.                   break;
  794.                case 2:
  795.                   if (disp >= 0) {
  796.                      state = 1;
  797.                      if (compbuf [compbufi2] == -1) {
  798.                         compbuf [compbufi1] += 3 + disp;
  799.                         compbuf [compbufi2] = 0;
  800.                         compbuf [compbufi] = 0;
  801.                      }
  802.                      else
  803.                         compbufi1 = compbufi;
  804.                   }
  805.                   else
  806.                      state = 0;
  807.                   break;
  808.             }
  809.             compbufi += (disp >= 0) ? disp + 1 : -disp + 1;
  810.          }
  811.          compbufi = 0;
  812.          while (compbufi < cols) {
  813.             disp = compbuf [compbufi];
  814.             putc (disp, iff);
  815.             if (disp < 0) {
  816.                putc (pl [plane][compbufi], iff);
  817.                for (col = compbufi; col <= (compbufi - disp); col++)
  818.                   pl [plane][col] = 0;
  819.             }
  820.             else
  821.                for (col = compbufi; col <= (compbufi + disp); col++) {
  822.                   putc (pl [plane][col], iff);
  823.                   pl [plane][col] = 0;
  824.                }
  825.             compbufi += (disp >= 0) ? disp + 1 : -disp + 1;
  826.          }
  827.       }
  828.       nextline:;
  829.    }
  830.    if (ftell (iff) & 1L)
  831.       putc (0, iff); /* Pad to word boundary */
  832.    printf ("   \x1B[1F\x1B[40K\n\x1BM");
  833. }
  834.  
  835.